Active Record Basics Guide Refresh, Encrypted Attributes Re-Optimization, and more... | This Week in Rails
https://world.hey.com/this.week.in.rails/active-record-basics-guide-refresh-encrypted-attributes-re-optimization-and-more-55c7b53f
Rails World 2024: Call for Proposals @ Sessionize.com
先週に引き続き、Rails World 2024のスピーカーの応募締切が2024-03-21に迫っているよ、というお知らせです
RF DOCS Active Record Basics Guide ci-skip by bhumi1102 · Pull Request #51226 · rails/rails · GitHub
Railsガイドの「Active Record Basics — Ruby on Rails Guides」の変更です
本文がサンプルコードを含めてたくさん変更されています
Memoize key_provider from key or deterministic key_provider if any by rosa · Pull Request #51324 · rails/rails · GitHub
ActiveRecordに関する変更です
このプルリクエストの作者は、自身のRailsアプリケーションをrailsのmainブランチで動かしてみたらテストコードの実行におよそ5倍の時間が掛かるようになったため、原因を調べてこのプルリクエストを出したそうです
どこに原因があったのか、プルリクエストで説明されています
前提として、ActiveRecord::Encryption::Schemeというクラスがあります
RailsにおけるModelの特定の属性を暗号化するための仕組みを提供するクラスです
このクラスに key_provider というメソッドがあります
このメソッドに関して、2024-02-09につくられたプルリクエストで変更が行なわれています
Remove memoization to accept key_provider overridden by with_encryption_context by jhawthorn · Pull Request #51019 · rails/rails · GitHub
もともと、この key_provider メソッドは、インスタンス変数をつかってメモ化されていました
このプルリクエストでは、そのインスタンス変数が意図しないタイミングで上書きされる場合があることを指摘して、メモ化の処理をなくす変更をしています
その変更が原因で、テストの実行に時間がかかるケースが発生するようになっていました
具体的にはModelの属性に対して、keyを明示的に渡す、あるいは、決定論的にkey_providerを宣言する場合です
この場合には、属性を読み込むたびにkey_providerをインスタンス化するためのキーを導出する必要があります
結果的に ActiveSupport::KeyGenerator#generate_key と OpenSSL::KDF.pbkdf2_hmac を何度も呼び出すことになり、大きなオーバーヘッドが発生します
今回のプルリクエストでは、属性に対してkeyを明示的に渡す場合、属性のkey_providerを決定論的に宣言する場合、について、それぞれインスタンス変数を使ってメモ化の処理を実装することで、オーバーヘッドを小さくし、処理の高速化を実現しています
MySQL 8.0.19 introduces aliases in the VALUES and SET clauses of INSERT INTO ... ON DUPLICATE KEY UPDATE statement by yahonda · Pull Request #51286 · rails/rails · GitHub
ActiveRecordに関する変更です
タイトル和訳は「MySQL 8.0.19 では、INSERT INTO ... ON DUPLICATE KEY UPDATE ステートメントの VALUES 句と SET 句にエイリアスが導入されています」
このプルリクエストではMySQL 8.0.0 ~ 8.0.18の場合に発生するエラーを修正しています
ActiveRecord::ConnectionAdapters::Mysql2Adapter クラスの実装において、INSERT INTO ... ON DUPLICATE KEY UPDATE ステートメントでVALUESのエイリアスを使用する処理が書かれていました
ただし、今回のプルリクエストの前までは、その処理に入る条件は「MySQL 8.0.0以上」となっていました
code:rb
if !mariadb? && database_version >= "8.0.0"
values_alias = quote_table_name("#{insert.model.table_name}_values")
sql = +"INSERT #{insert.into} #{insert.values_list} AS #{values_alias}"
MySQLにおいてこのステートメントでVALUESのエイリアスを使用できるのは8.0.19以降であるため、今回のプルリクエストでは該当の処理に入る条件を「MySQL 8.0.19以上」に修正しています